package cn.tanghom.support.db;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;

import cn.tanghom.app.system.aop.ConfigApplication;
import cn.tanghom.app.system.mapper.UserMapper;
import cn.tanghom.app.system.model.Role;
import cn.tanghom.support.page.Pager;
import cn.tanghom.support.page.Pagination;
import cn.tanghom.support.utils.GenericsUtils;

/**
 * 和SqlSession的区别是增加了domain operator
 * @author Hunteron-cp
 *
 * @param <T>
 * @param <PK>
 */

@Repository("baseCrudDao")
public class BaseCrudDao<T, PK extends Serializable> extends SqlSessionDaoSupport implements Serializable,CrudDaoSupport<T,PK> {
	
	private static final long serialVersionUID = 7623507504198633838L;

	private final String POSTFIX = "Mapper";
	
    // sqlmap.xml定义文件中对应的sqlid  
    public static final String SQLID_INSERT = "insert";  
    public static final String SQLID_INSERT_BATCH = "insertBatch";  
    public static final String SQLID_UPDATE = "update";  
    public static final String SQLID_UPDATE_PARAM = "updateByParams";  
    public static final String SQLID_UPDATE_BATCH = "updateBatch";  
    public static final String SQLID_DELETE = "delete";  
    public static final String SQLID_DELETE_PARAM = "deleteByParams";  
    public static final String SQLID_DELETE_BATCH = "deleteBatch";  
    public static final String SQLID_TRUNCATE = "truncate";  
    public static final String SQLID_SELECT = "find";  
    public static final String SQLID_SELECT_PK = "findById";  
    public static final String SQLID_SELECT_PARAM = "findByParams";  
    public static final String SQLID_SELECT_FK = "findByFk";  
    public static final String SQLID_COUNT = "count";  
    public static final String SQLID_COUNT_PARAM = "countByParams";  
    public static final String SQLID_EXECUTESQL = "executeSql"; 
	
    protected String namespace;	
	
	protected String pkColumnName = "id";

	public BaseCrudDao() {
		Class<T> clazz = (Class)GenericsUtils.getSuperClassGenricType(this.getClass());
		namespace = clazz.getSimpleName() + POSTFIX;	
		
		SqlSessionFactory factory = (SqlSessionFactory)ConfigApplication.getBean(SqlSessionFactory.class);
		this.setSqlSessionFactory(factory);
	}
	
	public BaseCrudDao(String namespace) {		
		this.namespace = namespace;
		
		SqlSessionFactory factory = (SqlSessionFactory)ConfigApplication.getBean(SqlSessionFactory.class);
		this.setSqlSessionFactory(factory);
	}
	
	
	public String getNameSpace() {
		return namespace;
	}
	
	public void setNameSpace(String namespace) {
		this.namespace = namespace;
	}
	
	/**
	@Resource(name = "sqlSessionTemplate")  
    public void setSuperSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {  
        super.setSqlSessionTemplate(sqlSessionTemplate);  
    } 
	*/
	
	@Autowired
	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
		super.setSqlSessionFactory(sqlSessionFactory);
	}
	
	
	@Override  
    public int insert(T entity) {  
        int rows = 0;  
        try {  
            rows = getSqlSession().insert(namespace + "." + SQLID_INSERT,  entity);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return rows;  
    }  
  
    @Override  
    public int update(T entity) {  
        int rows = 0;  
        try {  
            rows = getSqlSession().update(namespace + "." + SQLID_UPDATE,   entity);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return rows;  
    }  
  
    @Override  
    public int update(Map<String,Object> updates,Map<String,Object> where) {  
        int rows = 0;  
        try { 
        	Map<String,Object> params = updates;
        	if(where!=null){
        		updates.putAll(where);
        	}        	
            rows = getSqlSession().update(namespace + "." + SQLID_UPDATE_PARAM,  
            		params);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return rows;  
    }  
  
    @Override  
    public int delete(PK primaryKey) {  
        int rows = 0;  
        try {  
            rows = getSqlSession().delete(namespace + "." + SQLID_DELETE,  
                    primaryKey);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return rows;  
    }  
  
    @Override  
    public int delete(Map<String, Object> param) {  
        int rows = 0;  
        try {  
            rows = getSqlSession().delete(namespace + "." + SQLID_DELETE_PARAM,  
                    param);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return rows;  
    }  
  
    @Override  
    public int truncate() {  
        int rows = 0;  
        try {  
            rows = getSqlSession().delete(namespace + "." + SQLID_TRUNCATE);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return rows;  
    }  
  
    @Override  
    public int count() {  
        int result = 0;  
        try {  
            result = getSqlSession().selectOne(namespace + "." + SQLID_COUNT);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
  
    @Override  
    public int count(Object param) {  
        int result = 0;  
        try {  
            result = getSqlSession().selectOne(namespace + "." + SQLID_COUNT_PARAM,param);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
  
    @Override  
    public T get(PK primaryKey) {  
        try {  
            return getSqlSession().selectOne(namespace + "." + SQLID_SELECT_PK,primaryKey);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
  
    @Override  
    public List<T> findAll() {  
        try {  
            return getSqlSession().selectList(namespace + "." + SQLID_SELECT);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
          
    }  
     
  
    @Override  
    public List<T> findList(Map<String,Object> param) {  
        try {  
            return getSqlSession().selectList(namespace + "." + SQLID_SELECT_PARAM,param);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
  
    @Override  
    public Pager<T> findPage(Pagination pageEntity,Map<String,Object> param) {  
        try {  
            int page = pageEntity.getCurrentPage() == null ? 1 : pageEntity.getCurrentPage(); //默认为第一页  
            int size = pageEntity.getPageSize(); //默认每页10个  
              
            int totalSize = count(param);  
            
            RowBounds rowBounds = new RowBounds((page-1)*size, size);  
            if (param != null) {  
                param.put("orderColumn", pageEntity.getOrderBy());  
                param.put("orderTurn", pageEntity.getSortStr());  
            }else {  
            	param = new HashMap<String,Object>();  ;  
                param.put("orderColumn", pageEntity.getOrderBy());  
                param.put("orderTurn", pageEntity.getSortStr());  
            }  
              
            List<T> resultList = getSqlSession().selectList(namespace + "." + SQLID_SELECT_PARAM,param,rowBounds);  
           
              
            Pager<T> pagingResult = new Pager<T>(resultList);  
            pagingResult.setIndex(Long.valueOf(page));  
            pagingResult.setTotalRecord(Long.valueOf(totalSize));  
           
            return pagingResult;  
              
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
  
  
    @Override  
    public int insertBatch(List<T> list) {  
        try {  
            return getSqlSession().insert(namespace + "." + SQLID_INSERT_BATCH,list);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return 0;  
        }  
    }  
   
    @Override  
    public int updateBatch(List<T> list) {  
        int rows = 0;  
        try {  
            for (T t : list) {  
                rows = rows + getSqlSession().update(namespace + "." + SQLID_UPDATE, t);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return rows;  
  
    }  
  
    @Override  
    public int deleteBatch(List<PK> list) {  
        try {  
            return getSqlSession().delete(namespace + "." + SQLID_DELETE_BATCH,list);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return 0;  
        }  
  
    }  
      
    /** 
     * 日志打印 
     * @param sqlId 
     * @param param 
     */  
    public void printLog(String sqlId,Object param){  
        Configuration configuration = getSqlSession().getConfiguration();  
        //sqlId为配置文件中的sqlid  
        MappedStatement mappedStatement = configuration.getMappedStatement(sqlId);  
        //param为传入到sql语句中的参数  
        BoundSql boundSql = mappedStatement.getBoundSql(param);  
        //得到sql语句  
        String sql = boundSql.getSql().trim();  
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
        System.out.println("info-sql: "+sdf.format(new Date())+"  "+sql);  
    }  
    
	/** 
     * 获取全部对象 
     * @throws SQLException 
     */  
    @Override
     public <T> List<T> findList(String statementKey,Map<String,Object>  param) throws DataAccessException {  
         return getSqlSession().selectList(statementKey, param);  
     }  

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override 
	public <T>  Pager<T> findPage(String statementKey, Object parameter,
			int firstResult, int maxResult)  {
		Map params = new HashMap();
		if (parameter != null) {
			if (parameter instanceof Map) {
				params.putAll((Map) parameter);
			} else {
				Map parameterObject;
				try {
					parameterObject = PropertyUtils.describe(parameter);
					params.putAll(parameterObject);
				} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}
		RowBounds rowBounds = new RowBounds(firstResult, maxResult);  
		//PageHelper.startPage(pageForm.getPage(), pageForm.getRows());
		List<T> list = getSqlSession().selectList(statementKey, params, rowBounds);
		Pager<T> pageInfo = new Pager(list);

		return pageInfo;
	}

	public T findOne(Map<String,Object> param){
		T obj = getSqlSession().selectOne(this.namespace+"."+SQLID_SELECT_FK,param);  
		return obj;
	}

	public <T> T findOne(String statementKey, Map<String,Object> param) {
		T obj = getSqlSession().selectOne(statementKey,param);  
		return obj;
	}
	
	
	@SuppressWarnings("unchecked")	
	public <T> List<T> createQuery(String queryString) throws DataAccessException{
		String namespace = UserMapper.class.getName();		
		List<T> list = this.getSqlSession().selectList(namespace + SQLID_EXECUTESQL,queryString);
		return list;
	}
	
	
	@SuppressWarnings("unchecked")	
	public <T> List<T> createQuery(String queryString,int firstResult, int maxResult) throws DataAccessException{
		String namespace = UserMapper.class.getName();
		RowBounds rowBounds = new RowBounds(firstResult, maxResult); 
		List<T> list = this.getSqlSession().selectList(namespace + SQLID_EXECUTESQL,queryString,rowBounds);
		return list;
	}
	
	
	
	@Override	
	public int saveOrUpdate(T entity)	throws DataAccessException {
		BeanWrapper beanWrapper = new BeanWrapperImpl(entity);
		PK id = (PK)beanWrapper.getPropertyValue(pkColumnName);
		if (id == null) { // 添加
			return insert(entity);
		} else {			
			return update(entity);
		}
	}
	
	@Override
	public <T> T getBean(Class<T> obj, Serializable id) {		
		try {  
            return getSqlSession().selectOne(namespace + "." + SQLID_SELECT_PK,id);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
	
	}
	
	@Override
	public T unique(String sql) {
		String namespace = UserMapper.class.getName();
		T obj = getSqlSession().selectOne(namespace + "." + SQLID_EXECUTESQL);  
		return obj;		
	}
}

